/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
/**
 * 1. Promise是一个类，需要传入一个执行器，实现立即执行；
 * 2. 调用resolve 或者reject 的时候其实是在更改Promise 的状态
 * 3. Promise的三种状态：pending  fulfilled  rejected
 *      pending --> fulfilled
 *      pending --> rejected
 * 4. then方法内部即判断状态，如果状态为成功，即调用成功的回调函数，如果状态失败，调用失败的回调函数
 * 5. then成功回调有一个参数，表示成功之后的值；then失败的回调的参数，表示失败之后的原因
 * 6. then发放会被多次调用
 * 7. then方法是可以被链式调用的，后面的then方法的回调函数拿到的值是上一个then方法的回调函数的返回值
 */


const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
class MyPromise{
     constructor(executor){
        try{
            executor(this.resolve,this.reject)
        }catch(e){
            this.reject(e);
        }
        
     }
     status = PENDING;
     value = undefined;//立即执行成功的时候传入的参数，会被then的时候拿到
     reason = undefined;
     successCallback = [];//成功的回调
     failCallback = [];//失败的回调
     resolve = value =>{
        if(this.status != PENDING) return;
        this.status = FULFILLED;
        this.value = value;
      //   this.successCallback && this.successCallback(this.value);
        while(this.successCallback.length){
         this.successCallback.shift()();//shift移除数组的第一项并将其返回
        }
        
     }
     reject = reason =>{
        if(this.status != PENDING) return;
        this.status = REJECTED;
        this.reason = reason;
      //   this.failCallback && this.failCallback(reason);
      while(this.failCallback.length){
         this.failCallback.shift()();//shift移除数组的第一项并将其返回
        }
     }
     then(successCallback,failCallback){//接受成功和失败的回调 Promise.then((value)=>{},(reson)=>{})
      successCallback = successCallback ?successCallback :value => value;
      failCallback = failCallback ? failCallback : reason => {throw reason};
      let promise2 = new MyPromise((resolve,reject)=>{
         if(this.status === FULFILLED){
            setTimeout(()=>{//这里为异步程序是为了获取promise2
               try{
                  let x = successCallback(this.value);//成功回调会拿到resolve的表示成功的参数
                  //成功回调拿到的值有两种情形：普通值和promise对象
                  //普通值直接resolve,promise对象则根据该promise返回的结果来决定返回给下个then的执行状态及参数
                  // resolve(x);
                  //then方法当返回的是同一个promise对象的时候就要报错
                  resolvePromise(promise2, x, resolve, reject);
               }catch(e){
                  reject(e);
               }
            },0)
        }else if(this.status === REJECTED){
            // failCallback(this.reason);////失败回调会拿到reject的表示失败的参数
            setTimeout(()=>{//这里为异步程序是为了获取promise2
               try{
                  let x = failCallback(this.reason);//成功回调会拿到resolve的表示成功的参数
                  //成功回调拿到的值有两种情形：普通值和promise对象
                  //普通值直接resolve,promise对象则根据该promise返回的结果来决定返回给下个then的执行状态及参数
                  // resolve(x);
                  //then方法当返回的是同一个promise对象的时候就要报错
                  resolvePromise(promise2, x, resolve, reject);
               }catch(e){
                  reject(e);
               }
            },0)
        }else{//当Promise立即执行的函数里面有异步存在的时候，这时候成功或者失败的状态是未知的，即处于等待的状态，执行的回调也是未知的，因此需要把成功或者失败的回调函数的内容暂存下来，当立即执行函数被执行的时候且执行状态被确认，在执行成功或者失败回调
            // this.successCallback.push(successCallback);//当then被多次调用的时候，存在多个异步状态的情况下
            // this.failCallback.push(failCallback);
            this.successCallback.push(()=>{
               setTimeout(()=>{//这里为异步程序是为了获取promise2
                  try{
                     let x = successCallback(this.value);
                     resolvePromise(promise2, x, resolve, reject);
                  }catch(e){
                     reject(e);
                  }
               },0)
            });//当then被多次调用的时候，存在多个异步状态的情况下
            this.failCallback.push(()=>{
               setTimeout(()=>{//这里为异步程序是为了获取promise2
                  try{
                     let x = failCallback(this.reason);//成功回调会拿到resolve的表示成功的参数
                     resolvePromise(promise2, x, resolve, reject);
                  }catch(e){
                     reject(e);
                  }
               },0)
            });
        }
      })
        
      return promise2;
     }
     finally(callback){//promise回调失败还是成功，都执行finally;finally返回promise对象；当finally的callback(基本值或者promise对象)有异步的时候，执行完成，再执行后面的then方法
        return this.then(value=>{
           return MyPromise.resolve(callback()).then(()=>value) ;
        },reason=>{
         return MyPromise.resolve(callback()).then(()=>{throw reason}) ;
        })
     }
     catch (failCallback) {
         return this.then(undefined,failCallback);
     }
     static all (array) {
         //传入promise对象或者基本值
         let result = [];
         let index = 0;
         
         return new MyPromise((resolve,reject)=>{
            function add (key,value) {
               result[key] =value;
               index++;
               if(index === array.length){
                  resolve(result);
               }
            }
            for(let i = 0;i< array.length;i++){
               if(array[i] instanceof MyPromise){
                  
                  array[i].then(value => add(i,value),reason => reject(reason) )
               }else{
                  add(i,array[i]);
               }
            }   
         })
     }
     static resolve (value) {
         if (value instanceof MyPromise) return value;
         return new MyPromise((resolve)=>{resolve(value)});
     }

}
function resolvePromise (promise2,x,resolve,reject) {
   if(promise2 === x){
      return reject(new TypeError("Chaining cycle detected for promise #<Promise>"));
   }
   if(x instanceof MyPromise){
      x.then(resolve,reject);
   }else{
      resolve(x);
   }
}
module.exports = MyPromise;